Browser Object Model - Làm việc với trình duyệt
BOM (Browser Object Model) là tập hợp các đối tượng JavaScript cho phép bạn tương tác với trình duyệt web. Khác với DOM (Document Object Model) chỉ làm việc với nội dung trang web, BOM cho phép bạn điều khiển toàn bộ cửa sổ trình duyệt.
window - Đối tượng chính của trình duyệtlocation - Thông tin về URL hiện tạihistory - Lịch sử duyệt webnavigator - Thông tin về trình duyệtscreen - Thông tin về màn hìnhwindow là đối tượng toàn cục (global object) trong JavaScript trình duyệt. Tất cả các biến và function global đều là thuộc tính của window.
| Thuộc tính | Mô tả | Kiểu dữ liệu | Miền giá trị |
|---|---|---|---|
innerWidth |
Chiều rộng vùng nội dung cửa sổ (viewport) | Number | 0 - max screen width (px) |
innerHeight |
Chiều cao vùng nội dung cửa sổ (viewport) | Number | 0 - max screen height (px) |
outerWidth |
Chiều rộng toàn bộ cửa sổ (bao gồm border) | Number | 0 - screen width (px) |
outerHeight |
Chiều cao toàn bộ cửa sổ (bao gồm toolbar) | Number | 0 - screen height (px) |
scrollX |
Vị trí scroll ngang của document | Number | 0 - max scroll width (px) |
scrollY |
Vị trí scroll dọc của document | Number | 0 - max scroll height (px) |
screenX |
Vị trí X của cửa sổ trên màn hình | Number | -∞ to +∞ (px, có thể âm) |
screenY |
Vị trí Y của cửa sổ trên màn hình | Number | -∞ to +∞ (px, có thể âm) |
devicePixelRatio |
Tỷ lệ pixel vật lý/CSS pixel | Number | 0.5 - 5.0 (thường 1, 1.5, 2, 3) |
closed |
Kiểm tra cửa sổ đã đóng chưa | Boolean | true | false |
name |
Tên của cửa sổ (window target) | String | Bất kỳ string hợp lệ |
console.log("Chiều rộng:", window.innerWidth);
console.log("Chiều cao:", window.innerHeight);
console.log("Chiều rộng (bao gồm scrollbar):", window.outerWidth);
console.log("Chiều cao (bao gồm thanh công cụ):", window.outerHeight);
// Hiển thị thông báo
alert("Xin chào!");
// Xác nhận
let result = confirm("Bạn có chắc?");
// Nhập liệu
let name = prompt("Tên của bạn?");
// Mở cửa sổ mới
let newWindow = window.open(
"https://google.com",
"_blank",
"width=600,height=400"
);
// Đóng cửa sổ
newWindow.close();
// Cuộn đến vị trí
window.scrollTo(0, 500);
// Cuộn thêm
window.scrollBy(0, 100);
// Cuộn đến element
element.scrollIntoView();
window.location chứa thông tin về URL hiện tại và cho phép điều hướng trang.
| Thuộc tính | Mô tả | Kiểu dữ liệu | Miền giá trị/Ví dụ |
|---|---|---|---|
href |
URL đầy đủ (có thể ghi) | String | https://example.com/page?id=1#section |
protocol |
Giao thức URL (có thể ghi) | String | "http:", "https:", "ftp:", "file:" |
host |
Hostname + port (có thể ghi) | String | "example.com:8080", "localhost:3000" |
hostname |
Tên miền không có port (có thể ghi) | String | "example.com", "localhost", "192.168.1.1" |
port |
Số port (có thể ghi) | String | "", "80", "443", "3000", "8080" |
pathname |
Đường dẫn URL (có thể ghi) | String | "/", "/page", "/user/profile" |
search |
Query string bao gồm ? (có thể ghi) | String | "", "?id=1", "?name=John&age=25" |
hash |
Fragment bao gồm # (có thể ghi) | String | "", "#section", "#top", "#user-123" |
origin |
Protocol + hostname + port (read-only) | String | "https://example.com", "http://localhost:3000" |
// Cách 1: Gán trực tiếp
location.href = "https://google.com";
// Cách 2: Sử dụng assign() (tương đương)
location.assign("https://google.com");
// Đều lưu trang hiện tại vào history (có thể back)
// Thay thế trang hiện tại (KHÔNG lưu trong history)
location.replace("https://example.com");
// Người dùng KHÔNG thể back về trang này
// Thường dùng cho: login redirect, error pages
href/assign: Lưu trang hiện tại → có thể Backreplace: Không lưu trang hiện tại → KHÔNG thể Back// Tải lại trang (như nhấn F5)
location.reload();
// Tải lại trang từ server (bỏ qua cache)
location.reload(true); // Deprecated trong HTML5
// Cách mới để force reload
location.reload(); // Browser tự quyết định cache
| Method | Lưu History | Có thể Back | Khi nào dùng |
|---|---|---|---|
location.href |
✅ Có | ✅ Có | Navigation thông thường |
location.assign() |
✅ Có | ✅ Có | Tương đương href |
location.replace() |
❌ Không | ❌ Không | Login redirect, Error pages |
location.reload() |
- | - | Refresh trang hiện tại |
function loginSuccess() {
// Chuyển hướng đến dashboard
// Người dùng có thể back về trang login
location.href = "/dashboard";
}
// Sử dụng:
if (userCredentials.isValid) {
loginSuccess();
}
function sessionExpired() {
// Thay thế trang hiện tại bằng login
// KHÔNG cho phép back về trang cũ (bảo mật)
location.replace("/login");
}
// Sử dụng:
if (sessionToken.isExpired()) {
alert("Phiên đăng nhập đã hết hạn!");
sessionExpired();
}
function refreshData() {
// Tải lại trang để cập nhật dữ liệu mới
location.reload();
}
// Sử dụng:
document.getElementById('refreshBtn').onclick = () => {
if (confirm("Tải lại trang để cập nhật dữ liệu?")) {
refreshData();
}
};
function smartRedirect(url, options = {}) {
const {
replaceHistory = false,
confirm = true,
message = "Chuyển hướng đến trang mới?"
} = options;
if (confirm && !window.confirm(message)) {
return false;
}
if (replaceHistory) {
location.replace(url);
} else {
location.href = url;
}
return true;
}
// Sử dụng:
// Chuyển hướng thông thường
smartRedirect("/profile");
// Chuyển hướng không lưu history
smartRedirect("/login", {
replaceHistory: true,
message: "Về trang đăng nhập?"
});
href để user có thể backreplace để ngăn backreload() khi cần dữ liệu mớiwindow.history cho phép điều khiển lịch sử duyệt web của người dùng mà không cần tải lại trang.
| Thuộc tính/Method | Mô tả | Kiểu dữ liệu | Miền giá trị/Tham số |
|---|---|---|---|
length |
Số lượng entries trong history stack | Number (read-only) | 1 - không giới hạn |
scrollRestoration |
Kiểm soát việc restore scroll position | String | "auto" | "manual" |
state |
State object của history entry hiện tại | Any (read-only) | null | Object |
back() |
Quay lại 1 trang trong history | Method | Không có tham số |
forward() |
Tiến tới 1 trang trong history | Method | Không có tham số |
go(delta) |
Di chuyển delta bước trong history | Method | delta: Number (-∞ to +∞) |
pushState() |
Thêm entry mới vào history stack | Method | (state, title, url?) |
replaceState() |
Thay thế entry hiện tại trong history | Method | (state, title, url?) |
// Quay lại trang trước
history.back();
// Tiến tới trang sau
history.forward();
// Di chuyển n trang (âm = quay lại, dương = tiến tới)
history.go(-2); // Quay lại 2 trang
history.go(1); // Tiến tới 1 trang
// Thêm state mới vào history (không tải lại trang)
history.pushState({page: 1}, "Title", "/page1");
// Thay thế state hiện tại
history.replaceState({page: 2}, "Title", "/page2");
window.navigator chứa thông tin về trình duyệt và hệ điều hành của người dùng. Đây là một đối tượng chỉ đọc (read-only) cung cấp thông tin về môi trường trình duyệt.
| Thuộc tính | Mô tả | Kiểu dữ liệu | Miền giá trị |
|---|---|---|---|
userAgent |
Chuỗi định danh trình duyệt và hệ điều hành | String | Text chứa browser/OS info |
platform |
Nền tảng hệ điều hành | String | "Win32", "MacIntel", "Linux x86_64", etc. |
language |
Ngôn ngữ ưa thích của trình duyệt | String | ISO language codes: "en-US", "vi-VN", etc. |
languages |
Danh sách ngôn ngữ được hỗ trợ | Array | Array of language codes |
onLine |
Trạng thái kết nối internet | Boolean | true (online) | false (offline) |
cookieEnabled |
Cookie có được bật không | Boolean | true (enabled) | false (disabled) |
hardwareConcurrency |
Số lõi CPU logic | Number | 1 - 128+ (hoặc undefined) |
maxTouchPoints |
Số điểm chạm tối đa | Number | 0 (non-touch) - 10+ (multi-touch) |
deviceMemory |
RAM thiết bị (GB) - Chrome/Edge only | Number | 0.25, 0.5, 1, 2, 4, 8 (max 8GB vì privacy) |
connection |
Thông tin kết nối mạng | Object | NetworkInformation object |
geolocation |
API lấy vị trí địa lý | Object | Geolocation object |
permissions |
API kiểm tra quyền truy cập | Object | Permissions object |
serviceWorker |
API đăng ký Service Worker | Object | ServiceWorkerContainer object |
mediaDevices |
API truy cập camera/microphone | Object | MediaDevices object |
clipboard |
API truy cập clipboard | Object | Clipboard object |
// Thông tin cơ bản
console.log("User Agent:", navigator.userAgent);
console.log("Platform:", navigator.platform);
console.log("Ngôn ngữ:", navigator.language);
console.log("Trạng thái online:", navigator.onLine);
// Thông tin nâng cao
console.log("Cookie enabled:", navigator.cookieEnabled);
console.log("Hardware concurrency:", navigator.hardwareConcurrency);
console.log("Max touch points:", navigator.maxTouchPoints);
console.log("Languages:", navigator.languages);
function detectLanguage() {
const userLang = navigator.language || navigator.userLanguage;
const supportedLangs = navigator.languages || [userLang];
console.log("Ngôn ngữ chính:", userLang);
console.log("Danh sách ngôn ngữ:", supportedLangs);
// Chọn ngôn ngữ phù hợp cho website
if (userLang.startsWith('vi')) {
return 'vietnamese';
} else if (userLang.startsWith('en')) {
return 'english';
} else {
return 'english'; // Default
}
}
function detectDeviceCapabilities() {
// Thu thập thông tin từ browser APIs
const info = {
isMobile: navigator.maxTouchPoints > 0,
cpuCores: navigator.hardwareConcurrency || 'Unknown',
platform: navigator.platform || 'Unknown',
memoryGB: navigator.deviceMemory || 'N/A', // Chỉ Chrome/Edge
userAgent: navigator.userAgent
};
// ⚠️ LƯU Ý QUAN TRỌNG:
// Browser KHÔNG trả về thông tin hardware chính xác 100%
// Ví dụ: Máy M4 Pro RAM 24GB có thể chỉ hiện 8GB hoặc N/A
// Lý do: Privacy protection và security policies
let platformDesc = 'Unknown';
if (info.platform.includes('Mac')) {
platformDesc = 'macOS';
// Phát hiện Apple Silicon (M1, M2, M3, M4...)
if (!info.userAgent.includes('Intel')) {
platformDesc = 'macOS (Apple Silicon)';
}
}
// KHUYẾN NGHỊ: Sử dụng feature detection thay vì hardware detection
// ✅ Responsive design > device detection
// ✅ Performance testing > specs checking
return { platformDesc, ...info };
}
function setupOfflineMode() {
// Kiểm tra trạng thái ban đầu
updateConnectionStatus();
// Lắng nghe sự kiện thay đổi kết nối
window.addEventListener('online', () => {
console.log("🌐 Đã kết nối internet");
syncOfflineData(); // Đồng bộ dữ liệu offline
});
window.addEventListener('offline', () => {
console.log("🔌 Mất kết nối internet");
enableOfflineMode(); // Chuyển sang chế độ offline
});
}
// Lấy vị trí hiện tại
navigator.geolocation.getCurrentPosition(
function(position) {
console.log("Latitude:", position.coords.latitude);
console.log("Longitude:", position.coords.longitude);
console.log("Accuracy:", position.coords.accuracy);
},
function(error) {
console.log("Lỗi:", error.message);
// Error codes:
// 1: PERMISSION_DENIED
// 2: POSITION_UNAVAILABLE
// 3: TIMEOUT
},
{
enableHighAccuracy: true,
timeout: 10000,
maximumAge: 60000
}
);
Nếu không thể test với vị trí thật, hãy thử demo mô phỏng:
window.screen chứa thông tin về màn hình của người dùng. Đây là đối tượng chỉ đọc (read-only) cung cấp thông tin về phần cứng màn hình và không liên quan đến cửa sổ trình duyệt.
| Thuộc tính | Mô tả | Kiểu dữ liệu | Miền giá trị |
|---|---|---|---|
width |
Chiều rộng màn hình vật lý | Number | 320 - 7680+ pixels (1366, 1920, 2560, 3840...) |
height |
Chiều cao màn hình vật lý | Number | 240 - 4320+ pixels (768, 1080, 1440, 2160...) |
availWidth |
Chiều rộng khả dụng (trừ taskbar) | Number | ≤ screen.width pixels |
availHeight |
Chiều cao khả dụng (trừ taskbar) | Number | ≤ screen.height pixels |
colorDepth |
Độ sâu màu (bits per pixel) | Number | 8, 16, 24, 32 bits (thường 24 hoặc 32) |
pixelDepth |
Độ sâu pixel (bits per pixel) | Number | Thường bằng colorDepth (8, 16, 24, 32) |
orientation |
Đối tượng orientation (mobile/tablet) | Object | ScreenOrientation object (có thể null) |
orientation.type |
Kiểu hướng màn hình | String | "portrait-primary", "portrait-secondary", "landscape-primary", "landscape-secondary" |
orientation.angle |
Góc xoay của màn hình | Number | 0, 90, 180, 270 degrees |
availLeft |
Tọa độ X khả dụng đầu tiên | Number | 0+ pixels (multi-monitor) |
availTop |
Tọa độ Y khả dụng đầu tiên | Number | 0+ pixels (có taskbar top) |
// Kích thước màn hình vật lý
console.log("Độ phân giải màn hình:", screen.width + "x" + screen.height);
// Vùng làm việc (trừ taskbar)
console.log("Vùng làm việc:", screen.availWidth + "x" + screen.availHeight);
// Thông tin màu sắc
console.log("Độ sâu màu:", screen.colorDepth + " bits");
console.log("Độ sâu pixel:", screen.pixelDepth + " bits");
// Thông tin hướng màn hình (mobile)
console.log("Hướng màn hình:", screen.orientation?.type);
console.log("Góc xoay:", screen.orientation?.angle + "°");
function getScreenCategory() {
const width = screen.width;
const height = screen.height;
// Phân loại theo độ phân giải
if (width >= 3840 && height >= 2160) {
return "4K Ultra HD (3840x2160+)";
} else if (width >= 2560 && height >= 1440) {
return "2K/QHD (2560x1440+)";
} else if (width >= 1920 && height >= 1080) {
return "Full HD (1920x1080+)";
} else if (width >= 1366 && height >= 768) {
return "HD (1366x768+)";
} else {
return "Low Resolution";
}
}
function analyzeColorCapability() {
const colorDepth = screen.colorDepth;
const pixelDepth = screen.pixelDepth;
let colorInfo = {
depth: colorDepth,
totalColors: Math.pow(2, colorDepth),
quality: ""
};
if (colorDepth >= 32) {
colorInfo.quality = "Excellent (True Color + Alpha)";
} else if (colorDepth >= 24) {
colorInfo.quality = "Very Good (True Color)";
} else if (colorDepth >= 16) {
colorInfo.quality = "Good (High Color)";
} else {
colorInfo.quality = "Limited (256 colors or less)";
}
return colorInfo;
}
function setupOrientationTracking() {
// Kiểm tra hỗ trợ orientation
if (screen.orientation) {
console.log("Hướng hiện tại:", screen.orientation.type);
console.log("Góc xoay:", screen.orientation.angle);
// Lắng nghe thay đổi orientation
screen.orientation.addEventListener('change', () => {
console.log("Orientation changed to:", screen.orientation.type);
updateLayoutForOrientation();
});
}
}
function compareScreenVsWindow() {
const comparison = {
screen: {
total: \`\${screen.width}x\${screen.height}\`,
available: \`\${screen.availWidth}x\${screen.availHeight}\`
},
window: {
inner: \`\${window.innerWidth}x\${window.innerHeight}\`,
outer: \`\${window.outerWidth}x\${window.outerHeight}\`
},
taskbarSize: {
horizontal: screen.width - screen.availWidth,
vertical: screen.height - screen.availHeight
}
};
return comparison;
}
JavaScript cung cấp các function để thực thi code sau một khoảng thời gian nhất định hoặc lặp lại theo chu kỳ.
| Function | Mô tả | Tham số | Trả về |
|---|---|---|---|
setTimeout() |
Thực thi function sau delay time | (callback, delay, ...args) | Number (timeoutId) |
clearTimeout() |
Hủy timeout chưa thực thi | (timeoutId) | undefined |
setInterval() |
Thực thi function lặp lại theo chu kỳ | (callback, interval, ...args) | Number (intervalId) |
clearInterval() |
Dừng interval đang chạy | (intervalId) | undefined |
// Thực thi sau 3 giây
let timeoutId = setTimeout(() => {
console.log("Đã hết 3 giây!");
}, 3000);
// Hủy timeout
clearTimeout(timeoutId);
// Thực thi mỗi giây
let intervalId = setInterval(() => {
console.log("Tick!");
}, 1000);
// Hủy interval
clearInterval(intervalId);
Tạo một đồng hồ hiển thị thời gian hiện tại và cập nhật mỗi giây.
startClock() và stopClock()
Nhập một URL và phân tích các thành phần của nó.
parseURL()
Tạo dashboard hiển thị thông tin đầy đủ về Window, Location, Navigator, Screen.
loadBOMDashboard()
Phát hiện kích thước màn hình và hiển thị loại thiết bị.
detectDevice()
Tạo ứng dụng điều hướng với history management.
navigateToUrl(), replaceUrl(), addToHistory()
clearTimeout và clearInterval để tránh memory leaknavigator.onLine trước khi thực hiện network requestalert(), confirm() vì làm gián đoạn UXlocation.reload() không cần thiếtTại sao browser không trả về thông tin hardware chính xác?
Ví dụ thực tế:
✅ Thay thế tốt hơn:
Triệu chứng: "Geolocation API chỉ hoạt động trên HTTPS"
Giải pháp:
http://localhostTriệu chứng: "Quyền truy cập bị từ chối"
Giải pháp:
Triệu chứng: "Hết thời gian chờ"
Giải pháp:
Triệu chứng: "Vị trí không khả dụng"
Giải pháp:
if (navigator.geolocation)